package com.wangtianxiang.sxp.dbbase.config.resolve;

import com.alibaba.fastjson.JSONObject;
import com.wangtianxiang.sxp.dbbase.config.utils.JSONObjectUtil;
import com.wangtianxiang.sxp.dbbase.config.db.SxpDbConfigProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;

import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;

public class PropertiesResolve {
	private static final Logger logger = LoggerFactory.getLogger(PropertiesResolve.class);
	
	/**
	 * merge properties
	 * 
	 * @param propertySource
	 *            properties source.
	 * @param properties
	 *            the properies that exist, can be null.
	 * @param configPrefix
	 *            the properties name you want to limit
	 * @return
	 */
	private static Properties mergeProperties(PropertySource<?> propertySource, final Properties properties,
			String configPrefix) {
		OriginTrackedMapPropertySource compo = null;
		if (null == properties) {
			throw new IllegalArgumentException("'properties' must not be null");
		}
		if (null == propertySource) {
			return properties;
		}
		// CompositePropertySource
		if (propertySource instanceof OriginTrackedMapPropertySource) {
			compo = (OriginTrackedMapPropertySource) propertySource;
			String[] propertiesNames = compo.getPropertyNames();
			String keyTmp = null;
			for (String name : propertiesNames) {
				// filter config prifix if 'configPrefix' is not empty.
				keyTmp = name;
				if (null != configPrefix && !configPrefix.isEmpty()) {
					if (!name.startsWith(configPrefix)) {
						continue;
					}
					keyTmp  = name.substring(configPrefix.length() + 1).replaceAll("-", "").toLowerCase();
				}
				properties.put(keyTmp, compo.getProperty(name));
			}
		} else {
			// default logic
			Object source = propertySource.getSource();
			if (source instanceof Properties) {
				final Properties prop = (Properties) source;
				prop.keySet().stream().map(mapper -> {
					return mapper + "";
				}).filter(value -> {
					return ("" + value).startsWith(configPrefix);
				}).forEach(key -> {
					properties.put(key.substring(configPrefix.length() + 1).replaceAll("-", "").toLowerCase(),
							prop.get(key));
				});
			}
		}

		return properties;

	}

	public static <T> T resolve(MutablePropertySources propertyResolver, String configPrefix, Class<T> c) {

		if (null != propertyResolver) {
			// Properties
			final Map<String, Object> propertyMap = new TreeMap<String, Object>();
			Properties properties = new Properties();
			for (PropertySource<?> propertySource : propertyResolver) {
				logger.info(
						"scan config params, propertySource name :{},propertySource source's type:{}, all configNames:{}",
						propertySource.getName(), propertySource.getSource().getClass());
				mergeProperties(propertySource, properties, configPrefix);

			}
			properties.entrySet().forEach(entry -> {
				propertyMap.put("" + entry.getKey(), entry.getValue());
			});

			// format
			final JSONObject property = new JSONObject();
			propertyMap.forEach((key, value) -> {
				// format config key as json style
				int deep = key.replaceAll("[^(\\.)]", "").length();
				String tempV = value == null ? "" : value + "";
				String before = "{\"" + key.replaceAll("\\.", "\":{\"") + "\":";
				tempV = tempV.replaceAll("\\\\", "\\\\\\\\");
				tempV = tempV.replaceAll("\"", "\\\\\"");
				String after = "";
				while (after.length() <= deep) {
					after += "}";
				}
				String json = before + "\"" + tempV + "\"" + after;
				property.putAll(JSONObjectUtil.merge(JSONObject.parseObject(json, JSONObject.class), property));
			});
			if (logger.isTraceEnabled()) {
				logger.trace("Could not find xx in any property source");
			}
			return JSONObject.toJavaObject(property, c);
		}
		return null;
	}
	

	public static void main(String[] args) {
		String key = "a.b.c.ca.a-vvv-dd[0].ass.ap[0]";
		int deep = key.replaceAll("[^(\\.)]", "").length();
		String before = "{\"" + key.replaceAll("\\.", "\":{\"") + "\":";
		String value = "\\\\\121\"sa\\\\\\\\\\\\\\\"aa\"\\/\\\";s.w\"";
		System.out.println(value);
		value = value.replaceAll("\\\\", "\\\\\\\\");
		value = value.replaceAll("\"", "\\\\\"");
		// value =122+"";
		String after = "";
		while (after.length() <= deep) {
			after += "}";
		}
		System.out.println(before + "\"" + value + "\"" + after);
		System.out.println(JSONObject.parseObject(before + "\"" + value + "\"" + after).toJSONString());
		String json = "{\"datasouRces\":{\"DtASOURCES\":{\"username\":\"username\",\"password\":\"password\",\"driverclassname\":\"jdbc:xxx\",\"url\":\"192.168xxx\"},\"smsdatasouces\":{\"url\":\"192.168xxx\",\"password\":\"password\",\"p11assword\":\"password\",\"driverclassname\":\"jdbc:xxx\",\"username\":\"womusocdiy\"}},\"demo\":{\"name\":\"2000\",\"live\":\"1000\"}}";
		SxpDbConfigProperties wo = JSONObject.parseObject(json, SxpDbConfigProperties.class);
		System.out.println(JSONObject.toJSONString(wo));
	}

}
